﻿namespace SPDeploy.Library.Processing.Processors
{
    using System;
    using Data;
    using Exceptions;
    using Helpers;
    using Library;
    using Microsoft.SharePoint;
    using Action=SPDeploy.Data.Action;

    public class WebProcessor : ProcessorBase<Web, object>
    {
        #region Properties: public

        [ProcessorSetting(DefaultValue = IgnorableBehaviors.Ignore)]
        public IgnorableBehaviors AlreadyDeleted { get; set; }

        public override string Name
        {
            get { return "Web"; }
        }

        #endregion

        #region Methods: public

        public override object Install(ProcessorContext ctx, Web config)
        {
            Log(LogSeverity.Step, "{0} web titled '{1}'", Describe(ProcessorModes.Install, config.Action), config.Title);

            if (ctx.ParentResult != null && ctx.ParentResult is SPSite)
            {
                Log(LogSeverity.SubStep, "Parent site's root web ({0}) returned", (ctx.ParentResult as SPSite).Url);
                return (ctx.ParentResult as SPSite).RootWeb;
            }
            if (ctx.ParentResult != null && ctx.ParentResult is SPWeb)
            {
                var parentWeb = ctx.ParentResult as SPWeb;
                Log(LogSeverity.SubStep, "Absolute url: {0}", parentWeb.Url + "/" + config.Url);
                if (config.Action == Action.Lookup)
                {
                    return Lookup(ctx, config, parentWeb);
                }
                if (config.Action == Action.LookupOrCreate)
                {
                    SPWeb web = Lookup(ctx, config, parentWeb);
                    return web ?? CreateWeb(ctx, config, parentWeb);
                }
                return CreateWeb(ctx, config, parentWeb);
            }

            throw new DeploymentTargetProcessorException("Web processor did not receive a valid site or web instance");
        }

        public override object Uninstall(ProcessorContext ctx, Web config)
        {
            Log(LogSeverity.Step, "{0} '{1}' at '{2}'", Describe(ProcessorModes.Uninstall, config.Action), config.Title, config.Url);

            if (ctx.ParentResult != null && ctx.ParentResult is SPSite)
            {
                Log(LogSeverity.SubStep, "Parent site's root web returned - this will not be deleted");
                return (ctx.ParentResult as SPSite).RootWeb;
            }

            if (ctx.ParentResult != null && ctx.ParentResult is SPWeb)
            {
                if (config.Action == Action.Create)
                {
                    DeleteSubWebs(ctx, config);
                    DeleteWeb(ctx, config, ctx.ParentResult as SPWeb);
                    ctx.ChildrenDeleted = true;
                    return null;
                }
                return Lookup(ctx, config, ctx.ParentResult as SPWeb);
            }

            throw new DeploymentTargetProcessorException("Web processor did not receive a valid site or web instance");
        }

        public override object Update(ProcessorContext ctx, Web oldConfig, Web newConfig)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Methods: private

        private static SPWeb CreateWeb(ProcessorContext ctx, Web config, SPWeb parentWeb)
        {
            if (config.Url.IsEmpty() ||
                config.Title.IsEmpty() ||
                config.Template.IsEmpty())
            {
                throw new DeploymentTargetConfigException("The fields Title, Template and Url must all be defined for Site config nodes");
            }
            return parentWeb.Webs.Add(config.Url, config.Title, config.Description, (uint) config.LCID, config.Template, config.UniquePermissions, false);
        }

        private void DeleteSubWebs(ProcessorContext context, Web config)
        {
            foreach (Web subConfig in config.Webs)
            {
                Uninstall(context, subConfig);
            }
        }

        private static void DeleteWeb(ProcessorContext ctx, Web config, SPWeb parentWeb)
        {
            SPWeb web = Lookup(ctx, config, parentWeb);
            web.Delete();
        }

        private static SPWeb FindExistingWeb(SPWeb parentWeb, Web config)
        {
            SPWeb web = null;
            if (!config.Guid.IsEmpty())
            {
                var guid = new Guid(config.Guid);
                web = parentWeb.Webs[guid];
            }
            else
            {
                web = parentWeb.Webs[config.Url];
            }
            if (web == null)
            {
                throw new DeploymentTargetProcessorException(string.Format("Web could not be found with given guid ({0}) or url ({1})", config.Guid, config.Url));
            }
            return web;
        }

        private static SPWeb Lookup(ProcessorContext ctx, Web config, SPWeb parentWeb)
        {
            if (config.Guid.IsEmpty() && config.Url.IsEmpty())
            {
                throw new DeploymentTargetConfigException("Guid and Url cannot both be empty for Web config nodes");
            }
            return FindExistingWeb(parentWeb, config);
        }

        #endregion
    }
}